Class ControllerCrawler extends SRMonsterController;

var	float	LastPounceTime;
var	bool	bDoneSpottedCheck;

state ZombieHunt
{
	event SeePlayer(Pawn SeenPlayer)
	{
		if ( !bDoneSpottedCheck && PlayerController(SeenPlayer.Controller) != none )
		{
			// 25% chance of first player to see this Crawler saying something
			if(KFGameType(Level.Game)==none && SRGameType(Level.Game)!=none)
			{
				//Log("CrawlerController.SeePlayer None Error");
			}
			if ( !KFGameType(Level.Game).bDidSpottedCrawlerMessage && FRand() < 0.25 )
			{
				PlayerController(SeenPlayer.Controller).Speech('AUTO', 18, "");
				KFGameType(Level.Game).bDidSpottedCrawlerMessage = true;
			}
			bDoneSpottedCheck = true;
		}
		Super.SeePlayer(SeenPlayer);
	}
}

function bool IsInPounceDist(Actor PTarget)
{
	local vector DistVec;
	local float time;
	local float HeightMoved;
	local float EndHeight;

	//work out time needed to reach target
	if(Pawn==none) return false;
	DistVec = Pawn.location - PTarget.location;
	DistVec.Z=0;

	if(ZombieCrawler(Pawn)!=none)
		time = vsize(DistVec)/ZombieCrawler(Pawn).PounceSpeed;

	// vertical change in that time

	//assumes downward grav only
	HeightMoved = Pawn.JumpZ*time + 0.5*Pawn.PhysicsVolume.Gravity.z*time*time;
	EndHeight = Pawn.Location.z +HeightMoved;

	//log(Vsize(Pawn.Location - PTarget.Location));

	if(	KFMonster(Pawn)!=none && 
		(abs(EndHeight - PTarget.Location.Z) < Pawn.CollisionHeight + PTarget.CollisionHeight) &&
		VSize(Pawn.Location - PTarget.Location) < KFMonster(Pawn).MeleeRange * 5)
		return true;
	else
		return false;
}

function bool FireWeaponAt(Actor A)
{
	local vector aFacing,aToB;
	local float RelativeDir;

	if ( A == None )
		A = Enemy;
	if ( (A == None) || (Focus != A) )
		return false;

	if(CanAttack(A))
	{
		Target = A;
		if(Monster(Pawn)!=none)
			Monster(Pawn).RangedAttack(Target);
	}
	else
	{
		//TODO - base off land time rather than launch time?
		if((LastPounceTime + (4.5 - (FRand() * 3.0))) < Level.TimeSeconds )
		{
			aFacing=Normal(Vector(Pawn.Rotation));
			// Get the vector from A to B
			aToB=A.Location-Pawn.Location;
			RelativeDir = aFacing dot aToB;
			if ( RelativeDir > 0.85 )
			{
				//Facing enemy
				if(IsInPounceDist(A) )
				{
					if(ZombieCrawler(Pawn)!=none && ZombieCrawler(Pawn).DoPounce()==true )
						LastPounceTime = Level.TimeSeconds;
				}
			}
		}
	}
	return false;
}

function bool NotifyLanded(vector HitNormal)
{
	if(Pawn!=None && ZombieCrawler(Pawn)!=None && ZombieCrawler(Pawn).bPouncing )
	{
		// restart pathfinding from landing location
		GotoState('Hunting');
		return false;
	}
	else
		return Super.NotifyLanded(HitNormal);
}

state MonsterAvoid
{
	ignores EnemyNotVisible,SeePlayer,HearNoise;

	function AvoidThisMonster(KFMonster Feared)
	{
		GoalString = "AVOID MONSTER!";
		// Switch to the new guy if he is closer
		if(AvoidMonster!=none)
		{
			if (VSizeSquared(Pawn.Location - Feared.Location) < 
				VSizeSquared(Pawn.Location - AvoidMonster.Location))
			{
				AvoidMonster = Feared;
				BeginState();
			}
		}
	}

	function BeginState()
	{
		SetTimer(0.4,true);
	}

	event Timer()
	{
		local vector dir, side;
		local float dist;

		if ( AvoidMonster == None || AvoidMonster.Velocity dot (Pawn.Location - AvoidMonster.Location) < 0)
		{
                WhatToDoNext(11);

			return;
		}
		Pawn.bIsWalking = false;
		Pawn.bWantsToCrouch = False;
		dir = Pawn.Location - AvoidMonster.Location;
		dist = VSize(dir);
		if (dist <= AvoidMonster.CollisionRadius*NearMult)
			HitTheDirt();
		else if (dist < AvoidMonster.CollisionRadius*FarMult)
		{
			side = dir cross vect(0,0,1);
			// pick the shortest direction to move to
			if (side dot AvoidMonster.Velocity > 0)
				Destination = Pawn.Location + (-Normal(side) * (AvoidMonster.CollisionRadius*FarMult));
			else
				Destination = Pawn.Location + (Normal(side) * AvoidMonster.CollisionRadius*FarMult);

			GoalString = "AVOID VEHICLE!   Moving my arse..";
		}
	}

	function HitTheDirt()
	{
		local vector dir, side;

		GoalString = "AVOID Monster!   Jumping!!!";
		dir = Pawn.Location - AvoidMonster.Location;
		side = dir cross vect(0,0,1);
		Pawn.Velocity = Pawn.AccelRate * Normal(side);
		// jump the other way if its shorter
		if (side dot AvoidMonster.Velocity > 0)
			Pawn.Velocity = -Pawn.Velocity;
		Pawn.Velocity.Z = Pawn.JumpZ;
		bPlannedJump=True;
		Pawn.SetPhysics(PHYS_Falling);
	}

	function EndState()
	{
		bTimerLoop = False;
		AvoidMonster=None;
		Focus=None;
	}

Begin:
	WaitForLanding();
	MoveTo(Destination,AvoidMonster,False);
	if (AvoidMonster == None || VSize(Pawn.Location - AvoidMonster.Location) > AvoidMonster.CollisionRadius*FarMult || AvoidMonster.Velocity dot (Pawn.Location - AvoidMonster.Location) < 0)
	{
		WhatToDoNext(11);
		Warn("!! " @ Pawn.GetHumanReadableName() @ " STUCK IN AVOID MONSTER !!");
		GoalString = "!! STUCK IN AVOID MONSTER !!";
	}
	Sleep(0.2);
	GoTo('Begin');

}

function bool FindNewEnemy()
{
	return Class'ControllerAIBase'.Static.StaticFindNewEnemy(KFM,Self);
}
function bool SetEnemy( Pawn NewEnemy, optional bool bHateMonster )
{
	return Class'ControllerAIBase'.Static.StaticSetEnemy(KFM,Self,NewEnemy,bHateMonster);
}

defaultproperties
{
}
